//Doctor Office Simulation Program  Yuzhe Wu 2/3  16:50

#include "doctorOffice.h"
#include "list.h"
#include <cmath>
#include <stdio.h>
#include "copyright.h"
#include "system.h"
#include "synch.h"
#include <stdlib.h>
#include <limits.h>

//test by Tang

int verifyPatientID[MAXEXAMROOMNUM];
int nurseSheetIDTOPatient[MAXNURSENUM];
//The number of each entities
int examRoomNum = 5;
int docNum = 3;
int nurseNum = 5;
int xrayRoomNum = 2;
int patientNum = 100;
int parentNum = 1;


int bill=0;

//change by Tang
int patientLeftNum = 0;


//Lock defination

//1.The Lock with the Location
Lock waitingRoomLock("waitingRoomLock");
Lock examRoomLock[MAXEXAMROOMNUM];
Lock xrayRoomLock[MAXXRAYNUM];
Lock sittingRoomLock("sittingRoomLock");     //We imagine patient is waiting in an "Vitual" Room Called sitting room to wait for nurse to pick him up
											// When he finishes the interaction with WRN
Lock cashierRoomLock("cashierRoomLock");
Lock cabinetLock("cabinetLock");

Lock testLock("Lock");

//2. The Lock with the service providers
Lock wrnLock("wrnLock");
Lock nurseLock[MAXNURSENUM];
Lock docLock[MAXDOCNUM];
Lock cashierLock("cashierLock");

//3. The Lock for check state
Lock examStateLock("examStateLock");
Lock docStateLock("docStateLock");
Lock xrayStateLock("xrayStateLock");



//Condition variable defination
//1.Person waiting for Room CV
Condition patientWaitingWRCV("patientWaitingWRCV");
Condition nurseWaitingWRCV("nurseWaitingWRCV");
Condition patientWaitingCRCV("patientWaitingCRCV");
Condition nurseWaitingcabinetCV("nurseWaitingcabinetCV");


//2. Person waiting service providers at some Location
Condition patientWaitingNurseSRCV("patientWaitingNurseSRCV");
Condition nurseWaitingDocCV("nurseWaitingDocCV");
Condition patientWaitingNurseERCV[MAXEXAMROOMNUM];
Condition patientWaitingDocCV[MAXEXAMROOMNUM];
Condition patientWaitingNurseXRCV[MAXXRAYNUM];

//3. Person interaction CV
Condition wrnPatient_NurseCV("wrnPatient_NurseCV");
Condition nursePatientCV[MAXNURSENUM];
Condition docPatientCV[MAXDOCNUM];
Condition nurseXrayCV[MAXXRAYNUM];
Condition xrayPatientCV[MAXXRAYNUM];
Condition nurseDocCV[MAXDOCNUM];
Condition cashierPatientCV("cashierPatientCV");




//Moniter variable
//1. State 

bool wrnState = BUSY;
bool cashierState=BUSY;
bool cabinetState = FREE;				
bool examState[MAXEXAMROOMNUM];
bool docState[MAXDOCNUM];
bool xrayState[MAXXRAYNUM];



//2. Counter
int waitingRoomPatientCounter=0;
int waitingRoomNurseCounter=0;
int sittingRoomCounter=0;
int docRoomCounter=0;
int cashierRoomCounter=0;
int cabinetCounter=0;

//Global Varible
int wrnTask = WRONGTASK;
int patientORParent = WRONGPERSON; 


//Problem
int doc_NurseID = INT_MAX;  //The doctor id which response the nurse

//ID interchange
int nurseIDTOPatientSR = INT_MAX;
int patientIDTONurse = INT_MAX;
int parentIDTONurse = INT_MAX;
int nurseIDTOWRN = INT_MAX;
int docIDTOPatient[MAXEXAMROOMNUM];
int examIDTODoctor[MAXDOCNUM];
int examIDTOPatient[MAXNURSENUM];
int nurseIDTOXray[MAXXRAYNUM];
int docIDTONurse[MAXNURSENUM];
int nurseIDTOPatientER[MAXEXAMROOMNUM];
int xrayIDTOPatient[MAXNURSENUM];

int nurseIDTOPatientXR[MAXXRAYNUM];
int nurseIDVerify[MAXDOCNUM];
List *nurseIDList = new List();

//examSheet exchange
examSheet* wrnExamSheet = NULL;
examSheet* cashierExamSheet = NULL;
examSheet* wrnExamSheetEmpty = NULL;
examSheet* wallPocketER[MAXEXAMROOMNUM];
examSheet* xrayExamSheet[MAXXRAYNUM];
examSheet* wallPocketXR[MAXXRAYNUM];
examSheet* docExamSheet[MAXDOCNUM];





void Problem2 () {
	char c;
	
	printf("Please choose the case to test\n");
	printf("Case a: Child Patients are never abandoned by their Parent, nor go anywhere without their Parent\n");
	printf("Case b: Waiting Room Nurses only talk to on Patient/Parent at a time\n");
	printf("Case c: Cashier only talk to one Patient/Parent at a time\n");
	printf("Case d: Patients/Parents never go anywhere without being escorted by a Nurse\n");
	printf("Case e: All Patients leave the Doctor's Office.\n");
	printf("Case f: Two Doctors never examine the same Patient at the same time\n");
	printf("Case g: System Simulation: You need to enter the number of entities and rooms\n");
	printf("The command is: [a,b,c,d,e,f,g,q,h]\n");
	printf("command a,b,c,d,e,f,g is for different test, q is for quit, h is for help\n");
	printf( "\nPlease enter a command [a,b,c,d,e,f,g,q,h]: ");
		
	c=getchar();
		
	switch (c) {
	case 'a':
		printf("I am going to test case a\n\n");
		docNum = 1; nurseNum = 1;xrayRoomNum = 1;patientNum = 1;parentNum = 0;
		printf("SORRY: we do not have time for Parent/Child\n");
		printf("Please choose other test\n");
		break;

	case 'b':
		printf("Try: I am going to test case b\n\n");
		docNum = 0; nurseNum = 0;xrayRoomNum = 0;patientNum = 5;parentNum = 0;
		doctorOfficeSim();
		break;

	case 'c':
		printf("Try: I am going to test case c\n\n");
		docNum = 2; nurseNum = 2;xrayRoomNum = 1;patientNum = 5;parentNum = 0;
		doctorOfficeSim();
		break;

	case 'd':
		printf("Try: I am going to test case d\n\n");
		docNum = 2; nurseNum = 5;xrayRoomNum = 1;patientNum = 5;parentNum = 0;
		doctorOfficeSim();
		break;

	case 'e':
		printf("Try: I am going to test case e\n\n");
		docNum = 2; nurseNum = 5;xrayRoomNum = 2;patientNum = 5;parentNum = 0;
		doctorOfficeSim();
		break;

	case 'f':
		printf("Try: I am going to test case f\n\n");
		docNum = 2; nurseNum = 2;xrayRoomNum = 1;patientNum = 5;parentNum = 0;
		doctorOfficeSim();
		break;

	case 'g':
		printf("Try: I am going to test case g\n\n");
		//Get the input for prompt

		printf("Please enter the number of Doctors(2 to 3)\n");
		scanf("%d",&docNum );
		fflush(stdin);
		while ( !(docNum >=2&&docNum <=3)){ //Invalid input
			printf("You must input an Integer(2 to 3)\n");
			printf("Please reenter the number of Doctors(2 to 3)\n");
			scanf("%d",&docNum );
			fflush(stdin);			
		}
		
		printf("Please enter the number of Nurse(2 to 5)\n");
		scanf("%d",&nurseNum);
		fflush(stdin);
		while ( !(nurseNum>=2&&nurseNum<=5)){ //Invalid input
			printf("You must input an Integer(2 to 5)\n");
			printf("Please reenter the number of Nurses(2 to 5)\n");
			scanf("%d",&nurseNum);
			fflush(stdin);			
		}
		
		printf("Please enter the number of Examination Rooms(2 to 5)\n");
		scanf("%d",&examRoomNum);
		fflush(stdin);
		while ( !(examRoomNum>=2&&examRoomNum<=5)){ //Invalid input
			printf("You must input an Integer(2 to 5)\n");
			printf("Please reenter the number of Examination Rooms(2 to 5)\n");
			scanf("%d",&examRoomNum);
			fflush(stdin);			
		}
		
		printf("Please enter the number of Xray Technicians/Rooms(1 to 2)\n");
		scanf("%d",&xrayRoomNum);
		fflush(stdin);
		while ( !(xrayRoomNum>=1&&xrayRoomNum<=2)){ //Invalid input
			printf("You must input an Integer(1 to 2)\n");
			printf("Please reenter the number of Examination Rooms(1 to 2)\n");
			scanf("%d",&xrayRoomNum);
			fflush(stdin);			
		}
		
		printf("Please enter the number of Patients( >0)\n");
		scanf("%d",&patientNum);
		fflush(stdin);
		while ( !(patientNum>=0)){ //Invalid input
			printf("You must input an Integer(>0)\n");
			printf("Please reenter the number of Patients(>0)\n");
			scanf("%d",&patientNum);
			fflush(stdin);			
		}
		doctorOfficeSim();
		
		break;

	case 'h':
		printf("command a,b,c,d,e,f is for different test, q is for quit, h is for help\n\n");
		break;

	case 'q':
		break;

	default:
		printf("Invalid commands!\n\n");
		break;
	}

	

	/*
	printf("Number of Doctors(2 to 3):=[%d]\n",docNum);
	printf("Number of Nurse(2 - 5)=[%d]\n",nurseNum);
	printf("Number of Xray Technicians/Rooms(1 - 2)=[%d]\n",xrayRoomNum);
	printf("Number of Patients=[%d]\n",patientNum);
	printf("Number of Parents/Child Patients (30 or more)=[%d]\n",parentNum);
	printf("Number of Examination Rooms(2-5)=[%d]\n",examRoomNum);*/

}



void doctorOfficeSim() {

	Thread *t;
	int i = 0;
//Initialize the Array	
    //Initialize the State (3)
	
	//test verify by tang
	for (i=0;i<MAXEXAMROOMNUM;i++) {
		verifyPatientID[MAXEXAMROOMNUM] = INT_MAX;
	}
	for (i=0;i<MAXEXAMROOMNUM;i++) {
		nurseSheetIDTOPatient[MAXNURSENUM] = INT_MAX;
	}
	
	
	//end of test
	
	
	for (i=0;i<examRoomNum;i++) {
		examState[i] = FREE;
	}
	for (i=examRoomNum;i<MAXEXAMROOMNUM;i++) {
		examState[i] = BUSY;
	}	
	for (i=0; i<docNum; i++) {
		docState[i] = BUSY;
	}
	for (i=docNum; i<MAXDOCNUM; i++) {
		docState[i] = BUSY;
	}	
	for(i=0;i<xrayRoomNum;i++)
	{
		xrayState[i]=BUSY;  
	}	
	for(i=xrayRoomNum;i<MAXXRAYNUM;i++){
		xrayState[i]=BUSY;
	}	
	
	//Initialized the ID (9)
	
	for (i=0; i<MAXDOCNUM;i++) {
		examIDTODoctor[i] = INT_MAX;
	}	
	for(i=0; i<MAXNURSENUM;i++) {
		docIDTONurse[i] = INT_MAX;
	}	
	for (i=0; i<MAXNURSENUM;i++) {
		examIDTOPatient[i] = INT_MAX;
	}
	for (i=0; i<MAXEXAMROOMNUM; i++) {
		docIDTOPatient[i] = INT_MAX;
	}	
	for (i=0; i<MAXXRAYNUM; i++) {
		nurseIDTOXray[i]= INT_MAX;
	}
	
	for (i=0; i<MAXEXAMROOMNUM; i++) {
		nurseIDTOPatientER[i]= INT_MAX;
	}
	
	for(i=0; i<MAXNURSENUM; i++) {
		xrayIDTOPatient[i]= INT_MAX;
	}
	
	for(i=0; i<MAXXRAYNUM;i++) {
		nurseIDTOPatientXR[i] = INT_MAX;
	}
	
	for(i=0; i<MAXDOCNUM;i++) {
		nurseIDVerify[i] = INT_MAX;
	}

	
	//Initialized the examSheet 
	for (i=0; i<MAXEXAMROOMNUM;i++) {
		wallPocketER[i] = NULL;
	}
	
	for (i=0; i<MAXXRAYNUM;i++) {
		xrayExamSheet[i] = NULL;
	}
	
	for (i=0; i<MAXXRAYNUM;i++) {
		wallPocketXR[i] = NULL;
	}
	
	for (i=0; i<MAXDOCNUM;i++) {
		docExamSheet[i] = NULL;
	}
	
	
	
	
	printf("Number of Doctors(2 to 3):=[%d]\n",docNum);
	printf("Number of Nurse(2 - 5)=[%d]\n",nurseNum);
	printf("Number of Xray Technicians/Rooms(1 - 2)=[%d]\n",xrayRoomNum);
	printf("Number of Patients=[%d]\n",patientNum);
	printf("Number of Parents/Child Patients (30 or more)=[%d]\n",parentNum);
	printf("Number of Examination Rooms(2-5)=[%d]\n",examRoomNum);
    


    t = new Thread("t1");
    t->Fork((VoidFunctionPtr)waitingRoomNurse,0);

	for(i=0; i < patientNum; i++) {
		t = new Thread("t2");
		t->Fork((VoidFunctionPtr)patient,i);
	}

	for(i=0; i < nurseNum; i++) {
		t = new Thread("t3");
		t->Fork((VoidFunctionPtr)Nurse,i);
	}

	for(i=0; i < docNum; i++) {
		t = new Thread("t4");
		t->Fork((VoidFunctionPtr)doctor,i);
	}
	
	for(i=0; i < xrayRoomNum; i++) {
		t = new Thread("t5");
		t->Fork((VoidFunctionPtr)xray,i);
	}	

    t = new Thread("t6");
    t->Fork((VoidFunctionPtr)cashier,0);

}


void waitingRoomNurse(){


	List *wrnExamSheetList = new List();
	//change by Tang, add acquire two locks

	//printf("DEBUG: Enter waitingRoomNurse threads.\n");
	while(true) {
			
		waitingRoomLock.Acquire();
		//printf("DEBUG: waitingRoomNurse Again.\n");
		//printf("DEBUG: WRN Acquire Lock s!\n");
		if(waitingRoomNurseCounter>0) {  //A nurse is in line
			
			nurseWaitingWRCV.Signal(&waitingRoomLock);  //Let the nurse in the WR
			waitingRoomNurseCounter--;
			wrnState = BUSY;		
		}
		
		else if(waitingRoomPatientCounter>0) {	//A patient is in line
			
			patientWaitingWRCV.Signal(&waitingRoomLock);	//Let the patient in the WR
			waitingRoomPatientCounter--;
			wrnState = BUSY;
			
		}
		
		else {
			wrnState=FREE;	
		}
		
		wrnLock.Acquire();
		waitingRoomLock.Release();
		//printf("DEBUG: Start to wait!\n");
		wrnPatient_NurseCV.Wait(&wrnLock); //Wait for patient or nurse
		//printf("DEBUG: WRN is signal by patient!\n");
			
	//Interaction with Patient or Nurse
		
		//Check the three possible tasks: GETFORM GIVEFORM CALLPATIENT
		if(wrnTask == GETFORM ) {
			if ( patientORParent == PATIENT ) {
				printf("Waiting Room nurse gives a form to Adult patient [%d]\n",patientIDTONurse);
			}
			
			else if (patientORParent == PARENT) {
				printf("Waiting Room nurse gives a form to the Parent of Child patient [%d]\n",parentIDTONurse);
			}
			
			else {
				printf("ERROE: You get a wrong person neither the patient or parent\n");
			}
			//change by Tang, add acquire lock
//			waitingRoomLock.Acquire();
			wrnExamSheetEmpty = new examSheet();
			wrnPatient_NurseCV.Signal(&wrnLock);
			//printf("DEBUG: WRN is ready to wait!\n");
			wrnPatient_NurseCV.Wait(&wrnLock);
			//printf("DEBUG:WRN has given the examSheet to a patient.\n");
		}
		else if(wrnTask == GIVEFORM ) {
			wrnExamSheetList->Append((void *)wrnExamSheet);
			//printf("DEBUG:WaitingRoomNurse append           %d              patient in list\n\n\n\n\n\n\n", wrnExamSheet->patientID);
			wrnPatient_NurseCV.Signal(&wrnLock);
			//change by Tang
//			waitingRoomLock.Acquire();
			wrnPatient_NurseCV.Wait(&wrnLock);	
			//printf("DEBUG:WRN has put the a examSheet to a list.\n");
			printf("Waiting Room nurse accepts the form from Adult Patient/Parent with name [%s] and age [%d]\n", wrnExamSheet->name, wrnExamSheet->age);
			printf("Waiting Room nurse creates an examination sheet for [Adult/Child] patient with name [%s] and age [%d]\n", wrnExamSheet->name, wrnExamSheet->age);

			printf("Waiting Room nurse tells the Adult Patient/Parent [%s] to wait in the waiting room for a nurse\n", wrnExamSheet->name);


		}
		
		else if (wrnTask == CALLPATIENT) {
			wrnPatient_NurseCV.Signal(&wrnLock);
//			waitingRoomLock.Acquire();
			wrnPatient_NurseCV.Wait(&wrnLock);
			wrnExamSheet = (examSheet*) wrnExamSheetList->Remove();
			//printf("DEBUG:WaitingRoomNurse remove           %d              patient in list\n\n\n\n\n\n\n", wrnExamSheet->patientID);
			if(wrnExamSheet == NULL){
				printf("FATAL ERROR: no more ExamSheet for nurse.\n");
			}
			printf("Waiting Room nurse gives examination sheet to patient[%s] to Nurse [%d].\n",wrnExamSheet->name,nurseIDTOWRN);
			wrnPatient_NurseCV.Signal(&wrnLock);
			wrnPatient_NurseCV.Wait(&wrnLock);	

		}
		
		else {
			printf("\n\n\nERROR:WRONG WrnTask.\n\n\n");
		}
		wrnLock.Release();
						
	}
	
	
}


void patient(int index) {
	examSheet* myExamSheet = NULL;
	int myNurseID;
	int myExamID;
	int myXrayID;
	
	printf("Adult Patient [%d] has entered the Doctor's Office Waiting Room.\n",index);
	
	//Queuing to Get the form	
	waitingRoomLock.Acquire();
	//printf("DEBUG: patient Acquire Lock s!\n");
	
	if ( wrnState == BUSY) {
		//Nurse is busy, get in line
		waitingRoomPatientCounter++;
		printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to get registeration form.\n",index);
		patientWaitingWRCV.Wait(&waitingRoomLock);
	}
	else {	//wrn is FREE, server the patient
		wrnState = BUSY;
	}
	waitingRoomLock.Release();
	
	//Interaction patient&wrn,Get form
	//printf("DEBUG: Adult Patient [%d] prepare to get form.\n",index);
	wrnLock.Acquire();

	wrnTask = GETFORM;
	patientIDTONurse = index;
	patientORParent = PATIENT;
	//printf("DEBUG: Patient ready to signal wrn!\n");
	wrnPatient_NurseCV.Signal(&wrnLock);
	
	//printf("DEBUG: Patient have signaled wrn!\n");
	wrnPatient_NurseCV.Wait(&wrnLock);
	printf("[Adult patient/Parent of child patient][%d] gets the form from the Waiting Room Nurse.\n",index);
	myExamSheet = wrnExamSheetEmpty;
	//printf("DEBUG: Adult Patient [%d] get registeration form.\n",index);
	wrnPatient_NurseCV.Signal(&wrnLock);  //The patient get the examSheet
	wrnTask = 0;
	wrnLock.Release();
	
	
	//The patient fill out the examSheet
	myExamSheet->patientID = index;
	char nameString[30];
	snprintf(nameString,30,"Patient%d",index);
	myExamSheet->name = nameString;
	
	//Random Generate the patient age; Uniform distributed in [0 100]

	myExamSheet->age = rand()%100;
	
	//Generate sympton which is also the attribute of patient
	int symptonID = rand()%3;
	if(symptonID==0) {
		myExamSheet->symptom = "Pain";
	}
	else if(symptonID==1) {
		myExamSheet->symptom = "Nausea";
	}
	else if(symptonID==2) {
		myExamSheet->symptom = "Hear Alien Voices";
	}

	else {
		printf("ERROR: Wrong symptom\n");
	}
	//Finish filling out the form
	//printf("DEBUG: patient ready to give the form\n");
	//Queuing to give the form	
	waitingRoomLock.Acquire();
	//printf("DEBUG: patient Acquire Lock waitingRoomLock 2 s!\n");
	if ( wrnState == BUSY) {
		//Nurse is busy, get in line
		waitingRoomPatientCounter++;
		printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to submit registeration form.\n",index);
		patientWaitingWRCV.Wait(&waitingRoomLock);
	}
	else {	//wrn is FREE, server the patient
		wrnState = BUSY;
	}
	wrnLock.Acquire();
	waitingRoomLock.Release();
	
	//Interaction patient&wrn,Give form
	

	//printf("DEBUG: patient Acquire Lock wrnLock 2 s!\n");
	
	wrnTask = GIVEFORM;
	wrnExamSheet = myExamSheet;
	wrnPatient_NurseCV.Signal(&wrnLock);
	wrnPatient_NurseCV.Wait(&wrnLock);
	printf("[Adult patient/Parent of child patient][%d] submits the filled form to the Waiting Room Nurse.\n",index);
	sittingRoomLock.Acquire();
	//change by Tang
	wrnTask = 0;
/*	
	if(wrnExamSheet == NULL){
		printf("DEBUG: wrnExamSheet NULL!!!!!!!\n");
	}
	else{
		printf("DEBUG: wrnExamSheet not NULL\n");
	}
*/
	//printf("DEBUG: Adult Patient [%d] submit the examSheet e.\n",index);
	//I change!  +484
//	wrnPatient_NurseCV.Wait(&wrnLock);
	wrnPatient_NurseCV.Signal(&wrnLock);  //The patient give the examSheet
	
	
	

	
	
	//printf("DEBUG: Adult Patient [%d] gets finish the examSheet.\n",index);
	
	//The patient has get the examSheet
	
	//Patient interact with nurse
		
	wrnLock.Release();
	//printf("DEBUG:Patient [%d]waiting for nurse to come\n\n\n\n", index);
	sittingRoomCounter++;            //The patient is waiting in the waiting room
	testLock.Acquire();
	sittingRoomLock.Release();
	patientWaitingNurseSRCV.Wait(&testLock);  //Waiting for the nurse to call him up
	testLock.Release();
	myNurseID = nurseIDTOPatientSR;
	//printf("DEBUG:\n\nPatient [%d] is waken up by Nurse [%d] in waiting Room\n\n", index, myNurseID);
	
	/*
	if(index != myExamSheet->patientID){
		printf("DEBUG:FATAL ERROR: patient [%d] with wrong patient exam sheet with patientID at the very beginning%d \n\n\n\n", index, myExamSheet->patientID);
	}
		printf("DEBUG: patient [%d] nurse id is %d\n\n\n",index, myNurseID);
	if(nurseSheetIDTOPatient[myNurseID]!=index){
		
		printf("DEBUG:FATAL ERROR:patient [%d] the nurse get wrong examsheet with id %d from waiting room nurse.\n\n\n\n",index, nurseSheetIDTOPatient[myNurseID]);
	}
	*/
	
	while(nurseSheetIDTOPatient[myNurseID]!=index){
	
		currentThread->Yield();

	}

	nurseLock[myNurseID].Acquire();

	nursePatientCV[myNurseID].Signal(&nurseLock[myNurseID]);	
	myExamID = examIDTOPatient[myNurseID];

	 //Find the nurse to interaction with!
	nursePatientCV[myNurseID].Wait(&nurseLock[myNurseID]);
  //Wait for the nurse to wake him up with the proper examRoom index

	printf("[Adult Patient/Parent] [%s] is following Nurse [%d] to Examination Room [%d]\n", myExamSheet->name,myNurseID,myExamID);
	printf("[Adult Patient/Parent] [%s] has arrived at Examination Room [%d]\n", myExamSheet->name,myExamID);

	examRoomLock[myExamID].Acquire();
	nursePatientCV[myNurseID].Signal(&nurseLock[myNurseID]);
	
	
	nurseLock[myNurseID].Release();
	//printf("DEBUG: patient [%s] finish interaction with nurse\n", myExamSheet->name);
	patientWaitingDocCV[myExamID].Wait(&examRoomLock[myExamID]);

	//By now, I am waiting in exam rom for doctor
	//Start interaction doctor & patient
	int myDocID = docIDTOPatient[myExamID];
	//printf("DEBUG: Adult Patient [%s] has interact with Doctor [%d]\n",myExamSheet->name,myDocID);
	
	docLock[myDocID].Acquire();
	examRoomLock[myExamID].Release();

	docPatientCV[myDocID].Signal(&docLock[myDocID]);
	docPatientCV[myDocID].Wait(&docLock[myDocID]);
	myExamSheet = docExamSheet[myDocID];  //Get back the ExamSheet From Doc
	
	//verify
	/*
	if(index != docExamSheet[myDocID]->patientID){
		printf("DEBUG:FATAL ERROR: patient [%d] doctor give me the wrong examsheet with patient id %d\n\n\n\n\n", index, docExamSheet[myDocID]->patientID);
	}
	*/
	//printf("DEBUG: Patient [%s] receive the result from doc\n", myExamSheet->name);
	//printf("DEBUG:Patient find docExamSheet %d\n", docExamSheet[myDocID]->nextDestination);
	

	if(myExamSheet->needXray == true) {
		printf("Adult Patient [%s] has been informed by Doctor [%d] that he needs an Xray\n", myExamSheet->name,myDocID);
	}
	
	if(myExamSheet->needShot == true) {
		printf("Adult Patient [%s] has been informed by Doctor [%d] that he will be administered a shot\n", myExamSheet->name,myDocID);
	}

	
	printf("Adult Patient [%s] has been diagnosed by Doctor [%d]\n", myExamSheet->name,myDocID);
	

	//printf("DEBUG: Adult Patient [%s] has finish with Doctor [%d]\n", myExamSheet->name,myDocID);
	examRoomLock[myExamID].Acquire();
	docPatientCV[myDocID].Signal(&docLock[myDocID]);
	
	docLock[myDocID].Release();
	//printf("DEBUG: Adult Patient [%s] waiting in the ER [%d]\n", myExamSheet->name,myExamID);
	
	//using if to print doctor tell me where should I go to
	if(myExamSheet->nextDestination == XRAYROOM){
		if(strncmp(myExamSheet->name,"Patient",6) == 0)
			printf("Adult Patient [%d] waits for a Nurse to escort them to the Xray room.\n", myExamSheet->patientID);
		else
			printf("Parent [%d] waits for a Nurse to escort them to the Xray room.", myExamSheet->patientID);
	}
	
	patientWaitingNurseERCV[myExamID].Wait(&examRoomLock[myExamID]);
	
    examRoomLock[myExamID].Release();	

	//at exam room, goto exam room to take shot
	if(myExamSheet->needShot == true){	//need shot

		myNurseID = nurseIDTOPatientER[myExamID];
		printf("Adult Patient/Parent [%s] says, yes I am/He is ready for the shot?.\n", myExamSheet->name);
		nurseLock[myNurseID].Acquire();
		nursePatientCV[myNurseID].Signal(&nurseLock[myNurseID]);	//Start interacting with patient
		examRoomLock[myExamID].Acquire();
		nurseLock[myNurseID].Release();
		
		if(myExamSheet->needXray == true){	// if need xray, print wait for xray 
			if(strncmp(myExamSheet->name,"Patient",6) == 0){
				printf("Adult Patient [%d] waits for a Nurse to escort them to the Xray room.\n", myExamSheet->patientID);
			}
			else{
				printf("Parent [%d] waits for a Nurse to escort them to the Xray room.", myExamSheet->patientID);
			}
		}
		patientWaitingNurseERCV[myExamID].Wait(&examRoomLock[myExamID]);
		examRoomLock[myExamID].Release();
	}	//end of need shot
		
	//patient
	//at exam room, goto xray
	//wait at Xray room for nurse to take me to exam room
	//then interact with doctor at exam room
	//end up waiting nurse in exam room
	if(myExamSheet->needXray == true){	//need xray

		//get information from nurse, and then leave exam room
	
		myXrayID = xrayIDTOPatient[myExamID];
		//printf("DEBUG:Patient my xrayID is %d\n", myXrayID);
		examRoomLock[myExamID].Acquire();
		examState[myExamID] = FREE;
		//printf("DEBUG:Patient set the exam Room FREE");
		examRoomLock[myExamID].Release();
		xrayRoomLock[myXrayID].Acquire();
		
		//printf("DEBUG:PATIENT GONNA TO SIGNAL EXRAY MAN!!\n");
		xrayPatientCV[myXrayID].Signal(&xrayRoomLock[myXrayID]);
		
		// waiting for the instruction of XRay techinician
		xrayPatientCV[myXrayID].Wait(&xrayRoomLock[myXrayID]);
		//printf("DEBUG:pATIENT INTERACTED WITH XRAY MAN 1ST TIME\n");
		printf("[Adult Patient/Parent] [%s] gets on the table.\n",myExamSheet->name);
		printf("[Adult Patient/Parent] [%s] has been asked to take an Xray.\n",myExamSheet->name);
		xrayPatientCV[myXrayID].Signal(&xrayRoomLock[myXrayID]);
		
		
		if((myExamSheet->imageNum)>1)
		{
			int tmpi;	//temporary image taken number
			for(tmpi=0;tmpi<(myExamSheet->imageNum-1);tmpi++)
			{
			  xrayPatientCV[myXrayID].Wait(&xrayRoomLock[myXrayID]);
			  printf("[Adult Patient/Parent] [%s] moves for the next Xray\n",myExamSheet->name);
			  xrayPatientCV[myXrayID].Signal(&xrayRoomLock[myXrayID]);
			} 
		}
		
		xrayPatientCV[myXrayID].Wait(&xrayRoomLock[myXrayID]);	
		//printf("DEBUG:[Adult Patient/Parent] [%s]waits for a Nurse to escort him/her to Exam room.\n",myExamSheet->name);
		// first patient should wait fot waking up by nurse, and then he wakes the Xray Technician up.
		patientWaitingNurseXRCV[myXrayID].Wait(&xrayRoomLock[myXrayID]);	//wait for nurse take me to exam room
		xrayPatientCV[myXrayID].Signal(&xrayRoomLock[myXrayID]);
		xrayRoomLock[myXrayID].Release();
		
		myNurseID = nurseIDTOPatientXR[myXrayID];
		myExamID = examIDTOPatient[myNurseID];

		nurseLock[myNurseID].Acquire();
		examRoomLock[myExamID].Acquire();
		nursePatientCV[myNurseID].Signal(&nurseLock[myNurseID]);
		nurseLock[myNurseID].Release();
		patientWaitingDocCV[myExamID].Wait(&examRoomLock[myExamID]);

		//patient interact with doctor
		myDocID = docIDTOPatient[myExamID];
		docLock[myDocID].Acquire();
		//change by WU
		//docExamSheet[myDocID] = myExamSheet;
		docPatientCV[myDocID].Signal(&docLock[myDocID]);
		docLock[myDocID].Release();
		patientWaitingNurseERCV[myExamID].Wait(&examRoomLock[myExamID]);
		examRoomLock[myExamID].Release();
	}	//end of need xray

//	if(myExamSheet->nextDestination == CASHIER){	//goto cashier
		examRoomLock[myExamID].Acquire();
		examState[myExamID] = FREE;
		//printf("DEBUG:Patient set the exam Room FREE");
		/*
		if(verifyPatientID[myExamID] != index){
			printf("DEBUG:FATAL ERROR: patient [%d] this ER wall pocket examsheet %d is not mine, you are wrong.\n\n\n\n", index, verifyPatientID[myExamID]);
		
		}
		if(index!=myExamSheet->patientID){
			printf("DEBUG:FATAL ERROR: patient [%d] my examsheet and my id is not match my examsheet patientid %d.\n\n\n\n", index, myExamSheet->patientID);
		
		}
		*/
		examRoomLock[myExamID].Release();
		

		
		cashierRoomLock.Acquire();
		
		printf("[Adult Patient/Parent][%s]enters the queue of cashier\n",myExamSheet->name);
		//start to interact with cashier
		if(cashierState == FREE){
			cashierState=BUSY;
			cashierRoomLock.Release();
		}
		else{
			cashierRoomCounter++;
			patientWaitingCRCV.Wait(&cashierRoomLock);
			cashierRoomLock.Release();
		}
		// Enter the cahiser room and start interacting
		
		//print who reached cashier
		if(strncmp(myExamSheet->name,"Patient",6)==0){
			printf("Adult Patient ");
		}
		else{
			printf("Parent ");
		}
		printf("[%d] has reached cashier.\n", myExamSheet->patientID);
		
		cashierLock.Acquire();
		//printf("DEBUG:Patient [%d] :my name is %s\n", myExamSheet->patientID, myExamSheet->name);
		cashierExamSheet = myExamSheet;

		//printf("DEBUG:Patient [%d] :now cashier think myname is %s\n", myExamSheet->patientID, cashierExamSheet->name);
		
		if(strncmp(myExamSheet->name,"Patient",6)==0){
			printf("Adult Patient ");
		}
		else{
			printf("Parent ");
		}
		printf("[%d] hands over his examsheet to the cashier\n",myExamSheet->patientID);

		cashierPatientCV.Signal(&cashierLock);
		cashierPatientCV.Wait(&cashierLock);
		int money=bill;
		
		if(strncmp(myExamSheet->name,"Patient",6)==0){
			printf("Adult Patient ");
		}
		else{
			printf("Parent ");
		}
		printf("[%d] pays the cashier $ %d\n",myExamSheet->patientID, money);
		cashierPatientCV.Signal(&cashierLock);
		cashierPatientCV.Wait(&cashierLock);
		
		if(strncmp(myExamSheet->name,"Patient",6)==0){
		printf("Adult Patient ");
		}
		else{
			printf("Parent ");
		}
		printf("[%d] receives a receipt from the cashier\n",myExamSheet->patientID);
		cashierPatientCV.Signal(&cashierLock);
		
		//change by Tang
		patientLeftNum++;
		//printf("DEBUG: The number of patient that leave is %d \n", patientLeftNum);
		cashierLock.Release();
		
		if(strncmp(myExamSheet->name,"Patient",6)==0){
			printf("Adult Patient ");
		}
		else{
			printf("Parent ");
		}
		printf("[%d] leaves the doctor office.\n",myExamSheet->patientID);

//	}	//end of need casher

	
}


void Nurse(int id) { 	
	examSheet *myExamSheet;
	
	
	int myERID;	//the empty exam room I find to bring patient to
				//when patient in waiting room, or xray
	int myDocID;//the free doctor I find
				//when patient in exam room
	int myXRID; 
	int myWallPocketERID;	//the exam room No. which has a filled wall pocket
	int myWallPocketXRID;	//the eray room No. which has a filled wall pocket

	//printf("DEBUG: Nurse [%d]: I entered!\n", id);
	while(true){
		
//		printf("DEBUG:Nurse[%d]'s gonna to check waiting room\n", id);
		//check waiting Room if anyone waiting
		sittingRoomLock.Acquire();	//check if anyone is waiting
		if(sittingRoomCounter == 0){	//no one waiting
			sittingRoomLock.Release();
		}
		else{//some one waiting
	        
			//check Examination room state
			examStateLock.Acquire();
			for(myERID=0;myERID<examRoomNum;myERID++){
				if(examState[myERID] == FREE) {
					examState[myERID] = BUSY;
					//printf("DEBUG:Nurse%d find examRoom %d FREE\n",id,myERID);
					break;
				}
			}
			examStateLock.Release();
		
			if(myERID < examRoomNum){	//if any empty exam room
				sittingRoomCounter --;
				sittingRoomLock.Release();
				waitingRoomLock.Acquire();
				if(wrnState == BUSY){
					//nurse is busy, get in lines
					waitingRoomNurseCounter ++;
					nurseWaitingWRCV.Wait(&waitingRoomLock);
				}else{
					wrnState = BUSY;
				}
				
				
				testLock.Acquire();
				
				
				
				
				waitingRoomLock.Release();
				wrnLock.Acquire();
				wrnTask = CALLPATIENT;
				wrnPatient_NurseCV.Signal(&wrnLock);	//wake up wrn, start interacting
				wrnPatient_NurseCV.Wait(&wrnLock);
				printf("Nurse [%d] tells Waiting Room Nurse to give a new examination sheet.\n",id);
				nurseIDTOWRN= id;
				wrnPatient_NurseCV.Signal(&wrnLock);	
				wrnPatient_NurseCV.Wait(&wrnLock);
				//change by Tang
				wrnTask = 0;
				myExamSheet = wrnExamSheet;
				//printf("DEBUG:Nurse [%d]get a patient with name %s \n", id, myExamSheet->name);
				wrnPatient_NurseCV.Signal(&wrnLock);
				
				//prepare the data to interact with patient: nurseIDTOPatientSR
				nurseIDTOPatientSR = id;
				
				nurseSheetIDTOPatient[id] = myExamSheet->patientID;
				//wake patient up and let him wait for the nurse

				nurseLock[id].Acquire();				
				patientWaitingNurseSRCV.Signal(&testLock);
				testLock.Release();
				//printf("DEBUG:\n\nNurse[%d] try to wake up a patient with name %s\n",id, myExamSheet->name);


				//make sure wait nurseLock before p signal, 
					//get examsheet, end interacting with wrn
				
				
				//printf("DEBUG:\n\nNurse[%d] finish wake up a patient with name %s\n",id, myExamSheet->name);

				//change position of wrnLock release

				//bring patient in
				printf("Nurse [%d] escorts Adult/Child Patient [%s] to the examination room [%d].\n", id, myExamSheet->name, myERID);
				examIDTOPatient[id]=myERID;	
//change by Tang 860 -> 866

				
				nursePatientCV[id].Wait(&nurseLock[id]);	
				wrnLock.Release();
							
				nursePatientCV[id].Signal(&nurseLock[id]);				

				
				//interact with patient to do first exam
				
				printf("Nurse [%d] takes the temperature and blood pressure of Adult Patient/Parent [%s].\n", id, myExamSheet->name);
				printf("Nurse [%d] asks Adult Patient/Parent [%s] what Symptoms do you have?\n", id, myExamSheet->name);
				printf("Nurse [%d] writes all the information of Adult Patient/Parent [%s] in his examination sheet.\n", id, myExamSheet->name);
				
				//note right now patient need to get the ExamRoomLock
				nursePatientCV[id].Wait(&nurseLock[id]);
				//printf("DEBUG: Nurse [%d] finish Adult Patient/Parent [%s]\n",id, myExamSheet->name);
				nurseLock[id].Release();	//free the patient so that he can wait for the doctor
				
				
				//now go and bring a doctor
				docStateLock.Acquire();
				for(myDocID=0;myDocID<docNum;myDocID++){
					if(docState[myDocID] == FREE) {
						docState[myDocID] = BUSY;
						break;
					}
				}
				docStateLock.Release();
				
				if(myDocID >= docNum){	//no doctor free, wait
					docStateLock.Acquire();
					docRoomCounter++;
					//change by WU
					int *tmpNurseID = &id;
					nurseIDList->Append((void *)tmpNurseID);
					nurseWaitingDocCV.Wait(&docStateLock);
					myDocID = docIDTONurse[id];  //Doctor tell the nurse his ID
	/*
					if(id!=nurseIDVerify[myDocID]){
						printf("DEBUG FATAL ERROR: ERROR when pop and push nurse id in list\n");
					}
	*/
					nurseWaitingDocCV.Signal(&docStateLock);
					docStateLock.Release();
				}
				
				//by now, we get a doctor with # myDocID
				//we need to tell the doctor the exam room number and the patient id
				docLock[myDocID].Acquire();
//change by Tang, nurse hand in docExamSheet
				docExamSheet[myDocID] = myExamSheet;
				examIDTODoctor[myDocID]= myERID; 
				printf("Nurse [%d] informs Doctor [%d] that Adult/Child Patient [%s] is waiting in the examination room %d.\n", id, myDocID, myExamSheet->name,myERID);
				printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult/Child Patient [%s].\n", id, myDocID, myExamSheet->name);
				nurseDocCV[myDocID].Signal(&docLock[myDocID]);
				nurseDocCV[myDocID].Wait(&docLock[myDocID]);
				docLock[myDocID].Release();
				//printf("DEBUG: Nurse [%d] finish with Doctor [%d] \n", id, myDocID);
			}	//end of if any empty exam room
			else {	//no empty room
				sittingRoomLock.Release();
			}
			
		}	//end of else someone waiting
//	printf("DEBUG:Nurse not kazhu!\n");	
		nurseTaskDelay();

		//check Examination Room wall pocket
		for( myWallPocketERID=0;myWallPocketERID<examRoomNum;myWallPocketERID++){
			examRoomLock[myWallPocketERID].Acquire();
			if(wallPocketER[myWallPocketERID]!= NULL) {
	
				myExamSheet = wallPocketER[myWallPocketERID];
				//printf("DEBUG:Nurse[%d] find wall pocket exam [%d] filled.\n", id, myWallPocketERID);
				wallPocketER[myWallPocketERID] = NULL;
				examRoomLock[myWallPocketERID].Release();
				break;
			}
			examRoomLock[myWallPocketERID].Release();
		}
	

		if(myWallPocketERID<examRoomNum){//if any wall pocket, get inside and take patient to shot or Xray
			//printf("DEBUG:Nurse->nextDestination %d\n",myExamSheet->nextDestination);
			if(myExamSheet->nextDestination == EXAMROOM){	//take patient to shot
				cabinetLock.Acquire();
				if(cabinetState == BUSY){
					cabinetCounter++;
					nurseWaitingcabinetCV.Wait(&cabinetLock);
					//printf("DEBUG: nurse [%d] waiting for cabinet Lock.\n", id);
				}
				else{
					cabinetState = BUSY;
				}
				cabinetLock.Release();
				
				//by here, we need to get into the cabinet
				printf("Nurse [%d] goes to supply cabinet to give to take medicine for Adult/Child Patient [%s].\n", id, myExamSheet->name);
				cabinetLock.Acquire();
				if(cabinetCounter > 0){
					cabinetCounter --;
					nurseWaitingcabinetCV.Signal(&cabinetLock);
					//printf("DEBUG: Nurse [%d] Signal the cabinetCV", id);
				}
				else{
					cabinetState = FREE;
				}
				cabinetLock.Release();
				//by here, we got the medicine, and we need to give shot to patient

				
				examRoomLock[myWallPocketERID].Acquire();						
				nurseIDTOPatientER[myWallPocketERID] = id;	//prepare the data to interaction with patient
												//which exam room to go
				nurseLock[id].Acquire();
				printf("Nurse [%d] asks Adult/Child Patient [%s] \"Are you ready for the shot?\"\n", id, myExamSheet->name);
				patientWaitingNurseERCV[myWallPocketERID].Signal(&examRoomLock[myWallPocketERID]);
				
				examRoomLock[myWallPocketERID].Release();
				nursePatientCV[id].Wait(&nurseLock[id]);
				printf("Nurse [%d] tells Adult/Child Patient [%s] \"Your shot is over.\"\n", id, myExamSheet->name);
				
				if(myExamSheet->needXray == true){	//go to Xray
					//printf("DEBUG:Nurse[%d] find patient need Xray\n", id);
					myExamSheet->nextDestination = XRAYROOM;
				}else
				{
					myExamSheet->nextDestination = CASHIER;				
				}
				
				nurseLock[id].Release();
				//printf("DEBUG:nextDestination:%d",myExamSheet->nextDestination);				
				//printf("DEBUG:Nurse[%d] have given shot to patient[%d], and released my own nurse lock\n",id, myExamSheet->patientID);

			}	//end of if patient take shot

			if(myExamSheet->nextDestination == XRAYROOM){	// need go to Xray
				//printf("DEBUG:Nurse[%d] is checking xray state\n", id);
				//check xray room state
				xrayStateLock.Acquire();
				for(myXRID=0;myXRID<xrayRoomNum;myXRID++){
//					printf("DEBUG:Nurse[%d] is checking xray state %d\n", id, myXRID);
					if(xrayState[myXRID] == FREE){
						xrayState[myXRID] = BUSY;
//				printf("DEBUG:Nurse[%d] find empty xray room\n", id);
						xrayRoomLock[myXRID].Acquire();
						xrayExamSheet[myXRID] = myExamSheet;
						xrayRoomLock[myXRID].Release();
						break;
					}
				}
				xrayStateLock.Release();
				

				
				if(myXRID<xrayRoomNum){	//have empty xray room, go to xray

					examRoomLock[myWallPocketERID].Acquire();
//					xrayExamSheet[myXRID] = myExamSheet;
//					nurseIDTOPatientXR[myWallPocketERID] = id;
//					nurseIDTOXray[myXRID] = id;	//prepare data to interact with xray							
//					nurseLock[id].Acquire();			
					xrayIDTOPatient[myWallPocketERID] = myXRID;
			
//					nurseXrayCV[myXRID].Signal(&xrayRoomLock[myXRID]);	//wake up xray on nurseXrayCV, let him wait on xrayPatientCV			
//					xrayRoomLock[myXRID].Release();
//					nurseXrayCV[myXRID].Wait(&nurseLock[id]);
					printf("Nurse [%d] escorts %s to the X-ray room [%d].\n", id, myExamSheet->name, myXRID);
					patientWaitingNurseERCV[myWallPocketERID].Signal(&examRoomLock[myWallPocketERID]);
					examRoomLock[myWallPocketERID].Release();

	//				nurseLock[id].Release();
					//printf("DEBUG:Nurse left\n");
				}
				else{	//no empty room
					examRoomLock[myWallPocketERID].Acquire();
					wallPocketER[myWallPocketERID] = myExamSheet;
					examRoomLock[myWallPocketERID].Release();
				}
			}	//end of if go to next goto xray
			
			if(myExamSheet->nextDestination == CASHIER){
				examRoomLock[myWallPocketERID].Acquire();
				printf("Nurse [%d] escorts %s to Cashier.\n",id, myExamSheet->name);
				//test by Tang, verify
				verifyPatientID[myWallPocketERID] = myExamSheet->patientID;
				patientWaitingNurseERCV[myWallPocketERID].Signal(&examRoomLock[myWallPocketERID]);			
				examRoomLock[myWallPocketERID].Release();
			}//end of if need to go to cashier.
			
		}// end of if any wall pocket
		
		nurseTaskDelay();
	
//		printf("DEBUG:Nurse[%d]'s gonna to check xray room\n", id);	
		//check Xray Room wall pocket
		for(myWallPocketXRID=0;myWallPocketXRID<xrayRoomNum;myWallPocketXRID++){
			xrayRoomLock[myWallPocketXRID].Acquire();
			if(wallPocketXR[myWallPocketXRID] != NULL){
				myExamSheet = wallPocketXR[myWallPocketXRID];
				wallPocketXR[myWallPocketXRID] = NULL;
				//printf("DEBUG:Nurse [%d] find this myWallPocketXRID is not empty", myWallPocketXRID);
				//printf("DEBUG:Nurse [%d] find xray wall pocket with name %s ",id, myExamSheet->name);
				nurseIDTOPatientXR[myWallPocketXRID] = id;	//prepare the data to interact with patient
				xrayRoomLock[myWallPocketXRID].Release();
				break;
			}
			xrayRoomLock[myWallPocketXRID].Release();	
		}
		
		if(myWallPocketXRID<xrayRoomNum){
		//check if any empty examination room
		examStateLock.Acquire();
		for(myERID=0;myERID<examRoomNum;myERID++){
			if(examState[myERID] == FREE){
				examState[myERID] = BUSY;
				examRoomLock[myERID].Acquire();
				break;
			}
		}
		examStateLock.Release();
		
		if(myERID<examRoomNum){	//if any empty examination room
			
			xrayRoomLock[myWallPocketXRID].Acquire();
			nurseLock[id].Acquire();
			examIDTOPatient[id] = myERID;	//prepare the data to interact with patient
			examRoomLock[myERID].Release();
			printf("Nurse [%d] escorts %s to the examination room [%d].\n", id, myExamSheet->name,myERID);

			patientWaitingNurseXRCV[myWallPocketXRID].Signal(&xrayRoomLock[myWallPocketXRID]);
			xrayRoomLock[myWallPocketXRID].Release();
			nursePatientCV[id].Wait(&nurseLock[id]);
			nurseLock[id].Release();
			
			//nurse go to get the doctor
			
			docStateLock.Acquire();
			for(myDocID=0;myDocID<docNum;myDocID++){
				if(docState[myDocID] == FREE) {
					docState[myDocID] = BUSY;
					break;
				}
			}
			docStateLock.Release();
			
			if(myDocID >= docNum){	//no doctor free, wait
				docStateLock.Acquire();
				docRoomCounter++;
				//change by WU
				int *tmpNurseID = &id;
				nurseIDList->Append((void *)tmpNurseID);
				nurseWaitingDocCV.Wait(&docStateLock);
				myDocID = docIDTONurse[id];  //Doctor tell the nurse his ID
/*
				if(id!=nurseIDVerify[myDocID]){
					printf("DEBUG FATAL ERROR: ERROR when pop and push nurse id in list\n");
				}
*/
				nurseWaitingDocCV.Signal(&docStateLock);
	
				docStateLock.Release();
			}
			
			//by now, we get a doctor myDOCID
				docLock[myDocID].Acquire();
				docExamSheet[myDocID] = myExamSheet;
				examIDTODoctor[myDocID]= myERID; 
				printf("Nurse [%d] informs Doctor [%d] that Adult/Child Patient [%s] is waiting in the examination room %d.\n", id, myDocID, myExamSheet->name,myERID);
				printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult/Child Patient [%s].\n", id, myDocID, myExamSheet->name);
				nurseDocCV[myDocID].Signal(&docLock[myDocID]);
				nurseDocCV[myDocID].Wait(&docLock[myDocID]);
				docLock[myDocID].Release();
	
		}	//end of if any empty exam room

		else{	//if no empty exam room
			
			xrayRoomLock[myWallPocketXRID].Acquire();
			wallPocketXR[myWallPocketXRID] = myExamSheet;
			xrayRoomLock[myWallPocketXRID].Release();
		}	//end if no empty exam room
		}
		nurseTaskDelay();
	}// end-while

}


void doctor(int id)  {
	int mypatientERID = 0;
	int myNurseID;
	
	//printf("DEBUG: doctor [%d]: I entered!\n", id);
	while(true) {
		docStateLock.Acquire();
		if(docRoomCounter > 0) {  //A nurse is in line
			int *tmpNurseID = (int *)nurseIDList->Remove();			
			if(tmpNurseID == NULL){
				printf("DEBUG FATAL ERROR: doctor [%d] don't have nurse waiting.\n",id);	
			}
			myNurseID = *tmpNurseID;
			docIDTONurse[myNurseID] = id;
			nurseIDVerify[id] = myNurseID;
			docRoomCounter--;
			docState[id] = BUSY;			
			nurseWaitingDocCV.Signal(&docStateLock);
			//printf("DEBUG:doctor [%d] has waken up a nurse\n",id);
			nurseWaitingDocCV.Wait(&docStateLock);


		}
		else {    //No nurse is waiting, but which do not means the doctor should be idle
			docState[id] = FREE;
		}
		
		docLock[id].Acquire();
		docStateLock.Release();
		//printf("DEBUG: doctor [%d] is waiting for nurse\n", id);
		nurseDocCV[id].Wait(&docLock[id]);  //Wait for nurse
		
		mypatientERID = examIDTODoctor[id];
		nurseDocCV[id].Signal(&docLock[id]);
		docLock[id].Release();
		examRoomLock[mypatientERID].Acquire();
		//printf("DEBUG: Doctor [%d] is finish interact with nurse\n",id);
		printf("Doctor [%d] is leaving their office.\n", id);
		//Start interaction doctor & patient
		docIDTOPatient[mypatientERID] = id;
		docLock[id].Acquire();
		patientWaitingDocCV[mypatientERID].Signal(&examRoomLock[mypatientERID]);
		examRoomLock[mypatientERID].Release();
		
		docPatientCV[id].Wait(&docLock[id]);
		
		if(docExamSheet[id]->nextDestination == NOWHERE) {  //First interaction with patient
			printf("Doctor [%d] is reading the examination sheet of [Adult/Child] Patient [%s] in Examination room [%d]\n",id,docExamSheet[id]->name,mypatientERID);
			
			
			if (rand()%4 == 0) { //25% need a shot
				docExamSheet[id]->needShot = true;
				printf("Doctor [%d] notes down in the sheet that [Adult/Child] Patient [%s] needs to be given a shot in Examination room [%d]\n",id,docExamSheet[id]->name,mypatientERID);
			}
			else {
				docExamSheet[id]->needShot = false;
				
			}
			
			if (rand()%4 == 0) { //25% need a Xray
				docExamSheet[id]->needXray = true;
				printf("Doctor [%d] notes down in the sheet that Xray is needed for [Adult/Child] Patient [%s] in Examination room [%d]\n",id,docExamSheet[id]->name,mypatientERID);
				docExamSheet[id]->imageNum = rand()%3 + 1;
			}
			else {
				docExamSheet[id]->needXray = false;
			
			}
				
			if((docExamSheet[id]->needShot == false) && (docExamSheet[id]->needXray == false)) {
				printf("Doctor [%d] diagnoses [Adult/Child] Patient [%s] to be fine and is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,mypatientERID);
			}
			
			if(docExamSheet[id]->needShot == true){
				docExamSheet[id]->nextDestination = EXAMROOM;
			}
			else if(docExamSheet[id]->needXray == true){
				docExamSheet[id]->nextDestination = XRAYROOM;
			}
			else{
				docExamSheet[id]->nextDestination = CASHIER;
			}

			//printf("DEBUG: Doctor [%d] FIRST interact [Adult/Child] Patient [%s] is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,mypatientERID);		
			docPatientCV[id].Signal(&docLock[id]);
			docPatientCV[id].Wait(&docLock[id]);
			//printf("DEBUG DEBUG: Doctor [%d] FIRST interact [Adult/Child] Patient [%s] is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,mypatientERID);

			
		}
		else {  //Second interaction with Patient
			//printf("DEBUG DEBUG: Doctor [%d] SECOND interact [Adult/Child] Patient [%s] is leaving Examination Room [%d]\n",id,docExamSheet[id]->name,mypatientERID);
			if(strncmp(docExamSheet[id]->name, "Patient",6)==0){
				printf("Doctor [%d] is examining the Xrays of Adult Patient [%d] in Examination room [%d].\n", id, docExamSheet[id]->patientID, mypatientERID);
			}
			else{
				printf("Doctor [%d] is examining the Xrays of Child Patient [%d] in Examination room [%d].\n", id, docExamSheet[id]->patientID, mypatientERID);
			}

			printf("Doctor [%d] has left Examination Room [%d].\n", id, mypatientERID);
			docExamSheet[id]->nextDestination = CASHIER;
		}
	
		examRoomLock[mypatientERID].Acquire();
		wallPocketER[mypatientERID] = docExamSheet[id];  //Post the examSheet in the Wall pocket
		//printf("DEBUG: doctor[%d] put the exam sheet with name %s in wall pocket exam room\n", id, wallPocketER[mypatientERID]->name);
/*
		if(wallPocketER[mypatientERID]->needXray == false){
			printf("DEBUG:YOU DON'T NEED XRAY!!!!!!!\n");
		}
			else printf("DEBUG:YOU NEEEEEEED XRAY!!!!!!\n");
*/
			//printf("DEBUG:");
//		//printf("DEBUG:Doctor wallPocketER nextDEstination %d \n", wallPocketER[mypatientERID]->nextDestination);
		examRoomLock[mypatientERID].Release();
		//printf("DEBUG: doctor [%d] post the ES\n",id);
		docLock[id].Release(); //Doctor done with patient
		printf("Doctor [%d] is going to their office.\n", id);
	}


		

}


void cashier() {
	//printf("DEBUG: Cashier : I entered!\n");
	while(true){
    cashierRoomLock.Acquire();  // The similar scenario as what happened in the waiting room
	if(cashierRoomCounter>0){
		patientWaitingCRCV.Signal(&cashierRoomLock);
		cashierRoomCounter--;
		cashierState=BUSY;		
		//printf("DEBUG:cashier is BUSY now\n");
	}
	 else { 
		cashierState=FREE;// nobody is waiting in line 
		//printf("DEBUG:Cashier is FREE now\n");
	} 

	cashierLock.Acquire();
	cashierRoomLock.Release();
	cashierPatientCV.Wait(&cashierLock); // wait for patient to come
	
	
	if(strncmp(cashierExamSheet->name,"Patient",6)==0){
		printf("Cashier receives the examination sheet from Adult Patient [%s]\n",cashierExamSheet->name);
	}
	else{
		printf("Cashier receives the examination sheet for Child Patient [%d] from Parent [%d].\n", cashierExamSheet->patientID, cashierExamSheet->patientID);
	}
	
	
	bill=moneycalculate(cashierExamSheet);
	if(strncmp(cashierExamSheet->name,"Patient",6)==0){
		printf("Cashier reads the examination sheet of Adult Patient [%d] and asks him to pay $[%d].\n",cashierExamSheet->patientID, bill);
	}
	else{
		printf("Cashier reads the examination sheet of Child Patient [%d] and asks Parent [%d] to pay $[%d].\n", cashierExamSheet->patientID, cashierExamSheet->patientID,bill);
	}
	cashierPatientCV.Signal(&cashierLock); // Give the bill to the patient. Wait for money given
	cashierPatientCV.Wait(&cashierLock);
	                                  // wait for patient to pay money
	printf("Cashier accepts $[%d] from",bill);
	if(strncmp(cashierExamSheet->name,"Patient",6)==0){
		printf("Adult Patient [%d].\n",cashierExamSheet->patientID);
	}
	else{
		printf("Parent [%d].\n", cashierExamSheet->patientID);
	}
	                                 // Give the receipt to the patient
	printf("Cashier gives a receipt of $[%d] to ",bill);
	
	if(strncmp(cashierExamSheet->name,"Patient",6)==0){
		printf("Adult Patient [%d].\n",cashierExamSheet->patientID);
	}
	else{
		printf("Parent [%d].\n", cashierExamSheet->patientID);
	}
	cashierPatientCV.Signal(&cashierLock);
	cashierPatientCV.Wait(&cashierLock);
    cashierLock.Release();

	}
 }


void xray(int id) {
	int myNurseId;
	int i;
	examSheet * xraySheet;
	xrayRoomLock[id].Acquire();
	while(true){
	
		
		//printf("DEBUG: xray [%d]: I entered!\n", id);

/*		
		// waiting for the nurse to come in and wake him up
		nurseXrayCV[id].Wait(&xrayRoomLock[id]);
		
		myNurseId=nurseIDTOXray[id];
		nurseLock[myNurseId].Acquire();
		// Xray techinician gets the examsheet now
		xraySheet=xrayExamSheet[id];
		nurseXrayCV[id].Signal(&nurseLock[myNurseId]);
		nurseLock[myNurseId].Release();
*/		
//		xrayStateLock.Acquire();
		xrayState[id]=FREE;
//		xrayStateLock.Release();
//		xrayRoomLock[id].Release();
		
		//decide how many images the patients need to take
		//printf("DEBUG:XRAY MAN PREPARE TO WAIT!!!\n");
		xrayPatientCV[id].Wait(&xrayRoomLock[id]);
		xraySheet=xrayExamSheet[id];
		//printf("DEBUG:XRAY MAN WAKEN UP BY PATIENT\n");
		//interacion between patient and XRay techinician
	// 	following sequence of signal and printf changed by Tang
	// 	to synchronize with patient
	//	xrayPatientCV[id].Signal(&xrayRoomLock[id]);
		printf("Xray technician [%d] asks Adult Patient [%d] to get on the table.\n",id,xraySheet->patientID);
		xrayPatientCV[id].Signal(&xrayRoomLock[id]);
		xrayPatientCV[id].Wait(&xrayRoomLock[id]);
		printf("Xray Technician [%d] takes an Xray Image of Adult Patient [%d].\n",id,xraySheet->patientID);
		if((xraySheet->imageNum)>1)
		{
			for(i=0;i<xraySheet->imageNum-1;i++)
			{
				xrayPatientCV[id].Signal(&xrayRoomLock[id]);
				printf("Xray Technician [%d] asks Adult Patient [%d] to move.\n",id,xraySheet->patientID);
				xrayPatientCV[id].Wait(&xrayRoomLock[id]);
				printf("Xray Technician [%d] takes another Xray Image of Adult Patient [%d].\n",id,xraySheet->patientID);
			}
		}
		
		// record the result to the examination sheet

		if(rand()%3 == 0){  //1/3 to be nothing
			xraySheet->xrayResult=NOTHING;
		}
		else if(rand()%3 == 1){
				xraySheet->xrayResult = BREAK;
		}
		else xraySheet->xrayResult = COMPOUND;

		if(xraySheet->xrayResult == NOTHING){
			printf("Xray Technician [%d] records nothing on Adult Patient [%d]'s examination sheet.\n",id,xraySheet->patientID);
		}
		else if(xraySheet->xrayResult == BREAK){
			printf("Xray Technician [%d] records break on Adult Patient [%d]'s examination sheet.\n",id,xraySheet->patientID);
		}
		else if(xraySheet->xrayResult == COMPOUND){
			printf("Xray Technician [%d] records compound fracture on Adult Patient [%d]'s examination sheet.\n",id,xraySheet->patientID);
		}
		else {
			printf("ERROR: The X-ray technician give the wrong result\n");
		}
	//changed by Tang
	//changed the sequence of printf and Signal
		printf("X-ray Technician [%d] tells Patient [%d] to wait in Xray waiting room.\n",id,xraySheet->patientID);
		xrayPatientCV[id].Signal(&xrayRoomLock[id]);

	//changed by Tang
	//xraySheet->xrayExamsheet[id]
			//put the examsheet into the wall pocket and finish his task
		wallPocketXR[id] = xrayExamSheet[id];
		printf("Xray Technician put the examsheet into the wall pocket\n");
		//printf("DEBUG:Xray put the sheet with name %s in WallPocetXR\n", wallPocketXR[id]->name);
		xrayPatientCV[id].Wait(&xrayRoomLock[id]);

	}
}

 int moneycalculate(examSheet* Sheet) {// Calculate the total amount of the bill, Formular: money = basic($10) + shotmoney($50) + imageNum * moneyPerImage($30);	
	int money;
	money=BASIC;    
	if(Sheet->needShot==true){
		money+=SHOTMONEY;
	}
	if(Sheet->needXray==true){
		money+=(Sheet->imageNum)*IMAGEMONEY;
	}
	return money;
}

void nurseTaskDelay(){
	int r=rand()%100+50;
	int i;
	for(i=0;i<r;i++){
		currentThread->Yield();
	}
}

